Comenzamos con una visualizaci贸n est谩tica.
Terminamos con una visualuzaci贸n din谩mica e interactiva.
const width = 600;
const height = 400;
const margin = {
top: 30,
bottom: 30,
right: 30,
left: 30,
};
const svg = d3
.select("body")
.append("svg")
.attr("width", width)
.attr("height", height);
const boton = d3.select("body").append("button").text("Agregar elemento");
const parrafo = d3.select("body").append("p");
const contenedorEjeY = svg
.append("g")
.attr("transform", `translate(${margin.left}, ${margin.top})`);
const contenedorEjeX = svg
.append("g")
.attr("transform", `translate(${margin.left}, ${height - margin.bottom})`);
const contenedorBarras = svg
.append("g")
.attr("transform", `translate(${margin.left} ${margin.top})`);
function joinDeDatos(datos) {
const maximaFrecuencia = d3.max(datos, (d) => d.frecuencia);
const escalaAltura = d3
.scaleLinear()
.domain([0, maximaFrecuencia])
.range([0, height - margin.top - margin.bottom]);
const escalaY = d3
.scaleLinear()
.domain([0, maximaFrecuencia])
.range([height - margin.top - margin.bottom, 0]);
const ejeY = d3.axisLeft(escalaY);
contenedorEjeY
.transition()
.duration(1000)
.call(ejeY)
.selection()
.selectAll("line")
.attr("x1", width - margin.right - margin.left)
.attr("stroke-dasharray", "5")
.attr("opacity", 0.5);
const escalaX = d3
.scaleBand()
.domain(datos.map((d) => d.categoria))
.rangeRound([0, width - margin.right - margin.left])
.padding(0.5);
const ejeX = d3.axisBottom(escalaX);
contenedorEjeX
.transition()
.duration(1000)
.call(ejeX)
.selection()
.selectAll("text")
.attr("font-size", 20);
contenedorBarras
.selectAll("rect")
.data(datos, (d) => d.categoria)
.join(
(enter) =>
enter
.append("rect")
.attr("fill", "magenta")
.attr("y", height - margin.top - margin.bottom)
.attr("x", (d) => escalaX(d.categoria))
.attr("width", escalaX.bandwidth())
.attr("height", 0)
.transition()
.duration(1000)
.attr("height", (d) => escalaAltura(d.frecuencia))
.attr("y", (d) => escalaY(d.frecuencia))
.selection(),
(update) =>
update
.transition()
.duration(1000)
.attr("height", (d) => escalaAltura(d.frecuencia))
.attr("y", (d) => escalaY(d.frecuencia))
.attr("x", (d) => escalaX(d.categoria))
.attr("width", escalaX.bandwidth())
.selection(),
(exit) =>
exit
.transition()
.duration(500)
.attr("y", height - margin.top - margin.bottom)
.attr("height", 0)
.remove()
)
.on("mouseenter", (_, d) => {
parrafo.text(`Categor铆a: ${d.categoria}, Frecuencia: ${d.frecuencia}`);
})
.on("mouseleave", () => {
parrafo.text("");
})
.on("click", (_, d) => {
datos.splice(datos.indexOf(d), 1);
joinDeDatos(datos);
});
}
const datoNuevoRandom = (datos) => ({
categoria: String.fromCharCode(
datos[datos.length - 1].categoria.charCodeAt(0) + 1
),
frecuencia: Math.floor(Math.random() * 800),
});
let datos;
d3.json("datos.json")
.then((datosCargados) => {
console.log(datosCargados);
datos = datosCargados;
joinDeDatos(datos);
boton.on("click", () => {
datos.push(datoNuevoRandom(datos));
joinDeDatos(datos);
});
})
.catch((error) => console.log(error));
隆Hay muchos tipos de eventos!
click
dbclick
change
dragstart
dragover
Lista de eventos: MDN
const width = 600;
const height = 400;
const margin = {
top: 30,
bottom: 30,
right: 30,
left: 30,
};
const svg = d3
.select("body")
.append("svg")
.attr("width", width)
.attr("height", height);
const boton = d3.select("body").append("button").text("Agregar elemento");
const parrafo = d3.select("body").append("p");
const contenedorEjeY = svg
.append("g")
.attr("transform", `translate(${margin.left}, ${margin.top})`);
const contenedorEjeX = svg
.append("g")
.attr("transform", `translate(${margin.left}, ${height - margin.bottom})`);
const contenedorBarras = svg
.append("g")
.attr("transform", `translate(${margin.left} ${margin.top})`);
function joinDeDatos(datos) {
const maximaFrecuencia = d3.max(datos, (d) => d.frecuencia);
const escalaAltura = d3
.scaleLinear()
.domain([0, maximaFrecuencia])
.range([0, height - margin.top - margin.bottom]);
const escalaY = d3
.scaleLinear()
.domain([0, maximaFrecuencia])
.range([height - margin.top - margin.bottom, 0]);
const ejeY = d3.axisLeft(escalaY);
contenedorEjeY
.transition()
.duration(1000)
.call(ejeY)
.selection()
.selectAll("line")
.attr("x1", width - margin.right - margin.left)
.attr("stroke-dasharray", "5")
.attr("opacity", 0.5);
const escalaX = d3
.scaleBand()
.domain(datos.map((d) => d.categoria))
.rangeRound([0, width - margin.right - margin.left])
.padding(0.5);
const ejeX = d3.axisBottom(escalaX);
contenedorEjeX
.transition()
.duration(1000)
.call(ejeX)
.selection()
.selectAll("text")
.attr("font-size", 20);
contenedorBarras
.selectAll("rect")
.data(datos, (d) => d.categoria)
.join(
(enter) =>
enter
.append("rect")
.attr("fill", "magenta")
.attr("y", height - margin.top - margin.bottom)
.attr("x", (d) => escalaX(d.categoria))
.attr("width", escalaX.bandwidth())
.attr("height", 0)
.transition()
.duration(1000)
.attr("height", (d) => escalaAltura(d.frecuencia))
.attr("y", (d) => escalaY(d.frecuencia))
.selection(),
(update) =>
update
.transition()
.duration(1000)
.attr("height", (d) => escalaAltura(d.frecuencia))
.attr("y", (d) => escalaY(d.frecuencia))
.attr("x", (d) => escalaX(d.categoria))
.attr("width", escalaX.bandwidth())
.selection(),
(exit) =>
exit
.transition()
.duration(500)
.attr("y", height - margin.top - margin.bottom)
.attr("height", 0)
.remove()
)
.on("mouseenter", (_, d) => {
parrafo.text(`Categor铆a: ${d.categoria}, Frecuencia: ${d.frecuencia}`);
})
.on("mouseleave", () => {
parrafo.text("");
})
.on("click", (_, d) => {
datos.splice(datos.indexOf(d), 1);
joinDeDatos(datos);
});
}
const datoNuevoRandom = (datos) => ({
categoria: String.fromCharCode(
datos[datos.length - 1].categoria.charCodeAt(0) + 1
),
frecuencia: Math.floor(Math.random() * 800),
});
let datos;
d3.json("datos.json")
.then((datosCargados) => {
console.log(datosCargados);
datos = datosCargados;
joinDeDatos(datos);
boton.on("click", () => {
datos.push(datoNuevoRandom(datos));
joinDeDatos(datos);
});
})
.catch((error) => console.log(error));
Detalles de transiciones en subm贸dulo d3-transition
.
delay
para fijar un atraso.ease
para alterar como es el cambio en el tiempo.
selection.data(data);
selection.data(data, (d) => d.llave);
P谩gina intectiva de informaci贸n sobre armas nucleares.
Propuesta por estudiante "Java B".
(Fuente: Outrider - Nuclear Weapons Interactive)
Pr贸xima senaba revisaremos el material de Visualizaci贸n de datos tabulares y Layouts tabulares en D3.js.
Domingo 26 de septiembre (20:00:00) termina plazo de Hito 1.